#include "http/znx_http_parse.h"
#include "http/znx_http_request.h"
#include "comm/znx_log.h"

void test_readline()
{
    znx_buf_t               *buf;
    znx_http_readline_sm_t  sm;

    bzero(&sm, sizeof(znx_http_readline_sm_t));
    sm.max_line_size = 4096;

    buf = znx_buf_alloc_ext(128);
    strcpy((char *)buf->end, "AAAA\nBBB\nCCCC");
    buf->end += sizeof("AAAA\nBBB\nCCCC") - 1;

    if (znx_http_readline(&sm, buf) != ZNX_AGAIN) {
        ZNX_DEF_LOG_FATAL(NULL, "unexpect result");
    }

    strcpy((char *)buf->end, "DDDD\r\n");
    buf->end += sizeof("DDDD\r\n") - 1;

    if (znx_http_readline(&sm, buf) != ZNX_SUCCESS) {
        ZNX_DEF_LOG_FATAL(NULL, "unexpect result");
    }

    char    *str = "AAAA\nBBB\nCCCCDDDD\r\n";
    size_t  len = (size_t)strlen(str);
    if (sm.line.len != len || znx_strncmp(sm.line.data, (u_char *)str, len) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "unexpect result");
    }

    znx_buf_free(buf);
}


void test_header_parse()
{
    znx_http_header_t       header;

    znx_str_t str1 = {
        .data = (u_char *)"AAAA: 123",
        .len = sizeof("AAAA: 123") - 1
    };

    if (znx_http_parse_header_line(&str1, &header) != ZNX_HTTP_INVALID_HEADER_LINE) {
        ZNX_DEF_LOG_FATAL(NULL, "unexpect result");
    }

    znx_str_t str2 = {
        .data = (u_char *)"AAAA: 123\r\n",
        .len = sizeof("AAAA: 123\r\n") - 1
    };

    if (znx_http_parse_header_line(&str2, &header) != ZNX_SUCCESS) {
        ZNX_DEF_LOG_FATAL(NULL, "unexpect result");
    }

    if (header.name.len != 4 || znx_strncmp(header.name.data, "AAAA", 4) != 0) {
        ZNX_DEF_LOG_FATAL(NULL, "expect AAAA, but got other");
    }

    if (header.val.len != 3 || znx_strncmp(header.val.data, "123", 3) != 0) {
        ZNX_DEF_LOG_FATAL(NULL, "expect 123, but got other");
    }

    znx_str_t str3 = {
        .data = (u_char *)"AAAA: 123\n456\n789\n\r\n",
        .len = sizeof("AAAA: 123\n456\n789\n\r\n") - 1
    };

    if (znx_http_parse_header_line(&str3, &header) != ZNX_SUCCESS) {
        ZNX_DEF_LOG_FATAL(NULL, "unexpect result");
    }

    if (header.name.len != 4 || znx_strncmp(header.name.data, "AAAA", 4) != 0) {
        ZNX_DEF_LOG_FATAL(NULL, "expect AAAA, but got other");
    }

    if (header.val.len != 12 || znx_strncmp(header.val.data, "123\n456\n789\n", 12) != 0) {
        ZNX_DEF_LOG_FATAL(NULL, "expect 123\n456\n789\n, but got other");
    }
}


void test_update_uri_ext()
{
    znx_str_t        uri, uri_ext;

    uri.data = (u_char *)"/aaa/bbb/ccc/abc.txt";
    uri.len = sizeof("/aaa/bbb/ccc/abc.txt") - 1;
    uri_ext = znx_http_uri_ext(&uri);
    if (uri_ext.len != 4 || znx_strncmp(uri_ext.data, ".txt", 4) != 0) {
        ZNX_DEF_LOG_FATAL(NULL, "expect .txt, but got other");
    }

    uri.data = (u_char *)"/aaa/bbb/ccc/abc.txt/123.mp4";
    uri.len = sizeof("/aaa/bbb/ccc/abc.txt/123.mp4") - 1;
    uri_ext = znx_http_uri_ext(&uri);
    if (uri_ext.len != 4 || znx_strncmp(uri_ext.data, ".mp4", 4) != 0) {
        ZNX_DEF_LOG_FATAL(NULL, "expect .mp4, but got other");
    }

    uri.data = (u_char *)"/aaa/bbb/ccc/abc.txt.bak";
    uri.len = sizeof("/aaa/bbb/ccc/abc.txt.bak") - 1;
    uri_ext = znx_http_uri_ext(&uri);
    if (uri_ext.len != 4 || znx_strncmp(uri_ext.data, ".bak", 4) != 0) {
        ZNX_DEF_LOG_FATAL(NULL, "expect .bak, but got other");
    }

    uri.data = (u_char *)"/aaa/bbb/ccc/abc";
    uri.len = sizeof("/aaa/bbb/ccc/abc") - 1;
    uri_ext = znx_http_uri_ext(&uri);
    if (uri_ext.len != 0) {
        ZNX_DEF_LOG_FATAL(NULL, "expect NULL, but got other");
    }
}


static void
test_parse_request_uri()
{
    znx_http_request_t          request;

    bzero(&request, sizeof(znx_http_request_t));
    request.readline_sm.line.data = (u_char *)"GET /1.txt";
    request.readline_sm.line.len = sizeof("GET /1.txt") - 1;
    if (znx_http_parse_request_line(&request) == ZNX_SUCCESS) {
        ZNX_DEF_LOG_FATAL(NULL, "expect error, but got other");
    }

    bzero(&request, sizeof(znx_http_request_t));
    request.readline_sm.line.data = (u_char *)"GET /1.txt\r\n";
    request.readline_sm.line.len = sizeof("GET /1.txt\r\n") - 1;
    if (znx_http_parse_request_line(&request) != ZNX_HTTP_NO_SUPPORT_VERSION_9) {
        ZNX_DEF_LOG_FATAL(NULL, "expect ZNX_HTTP_NO_SUPPORT_VERSION_9, but got error");
    }

    bzero(&request, sizeof(znx_http_request_t));
    request.readline_sm.line.data = (u_char *)"GET /1.txt HTTP/1.0\r\n";
    request.readline_sm.line.len = sizeof("GET /1.txt HTTP/1.0\r\n") - 1;
    if (znx_http_parse_request_line(&request) != ZNX_SUCCESS) {
        ZNX_DEF_LOG_FATAL(NULL, "expect success, but got error");
    }
    if (request.method.len != 3 ||
        znx_strncmp(request.method.data, "GET", request.method.len) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect GET, but got other");
    }
    if (request.http_version != ZNX_HTTP_VERSION_10) {
        ZNX_DEF_LOG_FATAL(NULL, "expect ZNX_HTTP_VERSION_10, but got other");
    }
    if (request.request_uri.len != 6 ||
        znx_strncmp(request.request_uri.data, "/1.txt", 6) != 0 ||
        request.uri.len != 6 ||
        znx_strncmp(request.uri.data, "/1.txt", 6) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect /1.txt, but got other");
    }

    bzero(&request, sizeof(znx_http_request_t));
    request.readline_sm.line.data = (u_char *)"GET /1.txt?a=1&b=2 HTTP/1.1\r\n";
    request.readline_sm.line.len = sizeof("GET /1.txt?a=1&b=2 HTTP/1.1\r\n") - 1;
    if (znx_http_parse_request_line(&request) != ZNX_SUCCESS) {
        ZNX_DEF_LOG_FATAL(NULL, "expect success, but got error");
    }
    if (request.method.len != 3 ||
        znx_strncmp(request.method.data, "GET", request.method.len) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect GET, but got other");
    }
    if (request.http_version != ZNX_HTTP_VERSION_11) {
        ZNX_DEF_LOG_FATAL(NULL, "expect ZNX_HTTP_VERSION_11, but got other");
    }
    if (request.request_uri.len != 14 ||
        znx_strncmp(request.request_uri.data, "/1.txt?a=1&b=2", 14) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect /1.txt?a=1&b=2, but got other");
    }
    if (request.uri.len != 6 ||
        znx_strncmp(request.uri.data, "/1.txt", 6) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect /1.txt, but got other");
    }
    if (request.args.len != 7 ||
        znx_strncmp(request.args.data, "a=1&b=2", 7) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect a=1&b=2, but got other");
    }

    bzero(&request, sizeof(znx_http_request_t));
    request.readline_sm.line.data = (u_char *)"GET /1.txt?a=1&b=2#aaa HTTP/1.1\r\n";
    request.readline_sm.line.len = sizeof("GET /1.txt?a=1&b=2#aaa HTTP/1.1\r\n") - 1;
    if (znx_http_parse_request_line(&request) != ZNX_SUCCESS) {
        ZNX_DEF_LOG_FATAL(NULL, "expect success, but got error");
    }
    if (request.method.len != 3 ||
        znx_strncmp(request.method.data, "GET", request.method.len) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect GET, but got other");
    }
    if (request.http_version != ZNX_HTTP_VERSION_11) {
        ZNX_DEF_LOG_FATAL(NULL, "expect ZNX_HTTP_VERSION_11, but got other");
    }
    if (request.request_uri.len != 18 ||
        znx_strncmp(request.request_uri.data, "/1.txt?a=1&b=2#aaa", 18) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect /1.txt?a=1&b=2#aaa, but got other");
    }
    if (request.uri.len != 6 ||
        znx_strncmp(request.uri.data, "/1.txt", 6) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect /1.txt, but got other");
    }
    if (request.args.len != 7 ||
        znx_strncmp(request.args.data, "a=1&b=2", 7) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect a=1&b=2, but got other");
    }
    if (request.fragment.len != 3 ||
        znx_strncmp(request.fragment.data, "aaa", 3) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect aaa, but got other");
    }

    bzero(&request, sizeof(znx_http_request_t));
    request.readline_sm.line.data = (u_char *)"GET http://127.0.0.1/1.txt?a=1&b=2#aaa HTTP/1.1\r\n";
    request.readline_sm.line.len = sizeof("GET http://127.0.0.1/1.txt?a=1&b=2#aaa HTTP/1.1\r\n") - 1;
    if (znx_http_parse_request_line(&request) != ZNX_SUCCESS) {
        ZNX_DEF_LOG_FATAL(NULL, "expect success, but got error");
    }
    if (request.method.len != 3 ||
        znx_strncmp(request.method.data, "GET", request.method.len) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect GET, but got other");
    }
    if (request.http_version != ZNX_HTTP_VERSION_11) {
        ZNX_DEF_LOG_FATAL(NULL, "expect ZNX_HTTP_VERSION_11, but got other");
    }
    if (request.request_uri.len != 18 ||
        znx_strncmp(request.request_uri.data, "/1.txt?a=1&b=2#aaa", 18) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect /1.txt?a=1&b=2#aaa, but got other");
    }
    if (request.uri.len != 6 ||
        znx_strncmp(request.uri.data, "/1.txt", 6) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect /1.txt, but got other");
    }
    if (request.args.len != 7 ||
        znx_strncmp(request.args.data, "a=1&b=2", 7) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect a=1&b=2, but got other");
    }
    if (request.fragment.len != 3 ||
        znx_strncmp(request.fragment.data, "aaa", 3) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect aaa, but got other");
    }
    if (request.scheme.len != 4 ||
        znx_strncmp(request.scheme.data, "http", 4) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect http, but got other");
    }
    if (request.host.len != 9 ||
        znx_strncmp(request.host.data, "127.0.0.1", 9) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect 127.0.0.1, but got other");
    }

    bzero(&request, sizeof(znx_http_request_t));
    request.readline_sm.line.data = (u_char *)"GET http://[::1]/1.txt?a=1&b=2#aaa HTTP/1.1\r\n";
    request.readline_sm.line.len = sizeof("GET http://[::1]/1.txt?a=1&b=2#aaa HTTP/1.1\r\n") - 1;
    if (znx_http_parse_request_line(&request) != ZNX_SUCCESS) {
        ZNX_DEF_LOG_FATAL(NULL, "expect success, but got error");
    }
    if (request.method.len != 3 ||
        znx_strncmp(request.method.data, "GET", request.method.len) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect GET, but got other");
    }
    if (request.http_version != ZNX_HTTP_VERSION_11) {
        ZNX_DEF_LOG_FATAL(NULL, "expect ZNX_HTTP_VERSION_11, but got other");
    }
    if (request.request_uri.len != 18 ||
        znx_strncmp(request.request_uri.data, "/1.txt?a=1&b=2#aaa", 18) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect /1.txt?a=1&b=2#aaa, but got other");
    }
    if (request.uri.len != 6 ||
        znx_strncmp(request.uri.data, "/1.txt", 6) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect /1.txt, but got other");
    }
    if (request.args.len != 7 ||
        znx_strncmp(request.args.data, "a=1&b=2", 7) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect a=1&b=2, but got other");
    }
    if (request.fragment.len != 3 ||
        znx_strncmp(request.fragment.data, "aaa", 3) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect aaa, but got other");
    }
    if (request.scheme.len != 4 ||
        znx_strncmp(request.scheme.data, "http", 4) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect http, but got other");
    }
    if (request.host.len != 3 ||
        znx_strncmp(request.host.data, "::1", 3) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect ::1, but got other");
    }

    bzero(&request, sizeof(znx_http_request_t));
    request.readline_sm.line.data = (u_char *)"GET http://127.0.0.1:80/1.txt?a=1&b=2#aaa HTTP/1.1\r\n";
    request.readline_sm.line.len = sizeof("GET http://127.0.0.1:80/1.txt?a=1&b=2#aaa HTTP/1.1\r\n") - 1;
    if (znx_http_parse_request_line(&request) != ZNX_SUCCESS) {
        ZNX_DEF_LOG_FATAL(NULL, "expect success, but got error");
    }
    if (request.method.len != 3 ||
        znx_strncmp(request.method.data, "GET", request.method.len) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect GET, but got other");
    }
    if (request.http_version != ZNX_HTTP_VERSION_11) {
        ZNX_DEF_LOG_FATAL(NULL, "expect ZNX_HTTP_VERSION_11, but got other");
    }
    if (request.request_uri.len != 18 ||
        znx_strncmp(request.request_uri.data, "/1.txt?a=1&b=2#aaa", 18) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect /1.txt?a=1&b=2#aaa, but got other");
    }
    if (request.uri.len != 6 ||
        znx_strncmp(request.uri.data, "/1.txt", 6) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect /1.txt, but got other");
    }
    if (request.args.len != 7 ||
        znx_strncmp(request.args.data, "a=1&b=2", 7) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect a=1&b=2, but got other");
    }
    if (request.fragment.len != 3 ||
        znx_strncmp(request.fragment.data, "aaa", 3) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect aaa, but got other");
    }
    if (request.scheme.len != 4 ||
        znx_strncmp(request.scheme.data, "http", 4) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect http, but got other");
    }
    if (request.host.len != 9 ||
        znx_strncmp(request.host.data, "127.0.0.1", 9) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect 127.0.0.1, but got other");
    }
    if (request.port.len != 2 ||
        znx_strncmp(request.port.data, "80", 2) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect 80, but got other");
    }

    bzero(&request, sizeof(znx_http_request_t));
    request.readline_sm.line.data = (u_char *)"GET http://[::1]:80/1.txt?a=1&b=2#aaa HTTP/1.1\r\n";
    request.readline_sm.line.len = sizeof("GET http://[::1]:80/1.txt?a=1&b=2#aaa HTTP/1.1\r\n") - 1;
    if (znx_http_parse_request_line(&request) != ZNX_SUCCESS) {
        ZNX_DEF_LOG_FATAL(NULL, "expect success, but got error");
    }
    if (request.method.len != 3 ||
        znx_strncmp(request.method.data, "GET", request.method.len) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect GET, but got other");
    }
    if (request.http_version != ZNX_HTTP_VERSION_11) {
        ZNX_DEF_LOG_FATAL(NULL, "expect ZNX_HTTP_VERSION_11, but got other");
    }
    if (request.request_uri.len != 18 ||
        znx_strncmp(request.request_uri.data, "/1.txt?a=1&b=2#aaa", 18) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect /1.txt?a=1&b=2#aaa, but got other");
    }
    if (request.uri.len != 6 ||
        znx_strncmp(request.uri.data, "/1.txt", 6) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect /1.txt, but got other");
    }
    if (request.args.len != 7 ||
        znx_strncmp(request.args.data, "a=1&b=2", 7) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect a=1&b=2, but got other");
    }
    if (request.fragment.len != 3 ||
        znx_strncmp(request.fragment.data, "aaa", 3) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect aaa, but got other");
    }
    if (request.scheme.len != 4 ||
        znx_strncmp(request.scheme.data, "http", 4) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect http, but got other");
    }
    if (request.host.len != 3 ||
        znx_strncmp(request.host.data, "::1", 3) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect ::1, but got other");
    }

    if (request.port.len != 2 ||
        znx_strncmp(request.port.data, "80", 2) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect 80, but got other");
    }
}


void test_parse_trailer_header()
{
    znx_str_t           value;
    znx_http_trailers_t *trailers;
    znx_pool_t          *pool;

    pool = znx_pool_create();
    trailers = znx_http_trailers_create(pool);

    ZNX_STR_SET(&value, "aaa, bbb, ccc");
    znx_http_parse_trailer_header(pool, trailers, &value);

    ZNX_STR_SET(&value, "ddd,eee,fff");
    znx_http_parse_trailer_header(pool, trailers, &value);

    ZNX_STR_SET(&value, "ggg,");
    znx_http_parse_trailer_header(pool, trailers, &value);

    ZNX_STR_SET(&value, "hhh");
    znx_http_parse_trailer_header(pool, trailers, &value);

    if (trailers->total_trailers != 8) {
        ZNX_DEF_LOG_DEBUG(NULL, "expect 8, but got %d", trailers->total_trailers);
    }

    znx_pool_destroy(pool);
}


void test_parse_response_line()
{
    znx_http_request_t          request;
    znx_http_response_t         response;

    bzero(&request, sizeof(znx_http_request_t));
    bzero(&response, sizeof(znx_http_response_t));

    request.response = &response;
    response.request = &request;

    request.http_version = ZNX_HTTP_VERSION_11;
    request.readline_sm.line.data = (u_char *)"HTTP/1.1 200 OK\r\n";
    request.readline_sm.line.len = sizeof("HTTP/1.1 200 OK\r\n") - 1;

    if (znx_http_parse_response_line(&request) != ZNX_SUCCESS) {
        ZNX_DEF_LOG_FATAL(NULL, "expect success, but got other");
    }

    if (response.status_code != 200) {
        ZNX_DEF_LOG_FATAL(NULL, "expect 200, but got %d", response.status_code);
    }

    if (response.status_reason.len != 2 ||
        znx_strncmp(response.status_reason.data, "OK", 2) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect OK, but got %v", &response.status_reason);
    }

    request.http_version = ZNX_HTTP_VERSION_11;
    request.readline_sm.line.data = (u_char *)"HTTP/1.1 99 OK\r\n";
    request.readline_sm.line.len = sizeof("HTTP/1.1 99 OK\r\n") - 1;

    if (znx_http_parse_response_line(&request) == ZNX_SUCCESS) {
        ZNX_DEF_LOG_FATAL(NULL, "expect failed, but got success");
    }

    request.http_version = ZNX_HTTP_VERSION_10;
    request.readline_sm.line.data = (u_char *)"HTTP/1.0 400 Bad Request\r\n";
    request.readline_sm.line.len = sizeof("HTTP/1.0 400 Bad Request\r\n") - 1;

    if (znx_http_parse_response_line(&request) != ZNX_SUCCESS) {
        ZNX_DEF_LOG_FATAL(NULL, "expect success, but got other");
    }

    if (response.status_code != 400) {
        ZNX_DEF_LOG_FATAL(NULL, "expect 400, but got %d", response.status_code);
    }

    if (response.status_reason.len != 11 ||
        znx_strncmp(response.status_reason.data, "Bad Request", 11) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect OK, but got %v", &response.status_reason);
    }
}


void test_check_host_valid()
{
    znx_http_request_t  request;
    bzero(&request, sizeof(znx_http_request_t));
    request.pool = znx_pool_create();

    ZNX_STR_SET(&request.host, "www.aaa.com:123");
    if (znx_http_validate_host(&request) != ZNX_SUCCESS ||
        request.host.len != 11 ||
        znx_strncmp("www.aaa.com", request.host.data, request.host.len) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect www.aaa.com, but got %v", &request.host);
    }

    ZNX_STR_SET(&request.host, "www.AAA.com:123");
    if (znx_http_validate_host(&request) != ZNX_SUCCESS ||
        request.host.len != 11 ||
        znx_strncmp("www.aaa.com", request.host.data, request.host.len) != 0)
    {
        ZNX_DEF_LOG_FATAL(NULL, "expect www.aaa.com, but got %v", &request.host);
    }

    znx_pool_destroy(request.pool);
}


int main()
{
    test_readline();
    test_header_parse();
    test_update_uri_ext();
    test_parse_request_uri();
    test_parse_trailer_header();
    test_parse_response_line();
    test_check_host_valid();

    ZNX_DEF_LOG_DEBUG(NULL, "test pass");
    return 0;
}